<?php

namespace maotool\object;


use Closure;
use maotool\core\annotation\old\base\ParamWrapper;
use maotool\core\annotation\old\base\ReturnWrapper;
use maotool\core\annotation\old\base\VarWrapper;
use maotool\core\lang\Usage;
use maotool\exception\ClassNotFoundException;
use maotool\exception\MethodNotFoundException;
use maotool\file\DirUtil;
use maotool\file\FileUtil;
use maotool\script\PhpScriptUtil;
use maotool\util\ArrayUtil;
use maotool\util\DateUtil;
use maotool\util\PathUtil;
use maotool\util\ShellUtil;
use ReflectionClass;
use ReflectionException;
use ReflectionFunction;
use ReflectionMethod;
use ReflectionProperty;

/**
 * 类反射工具
 */
class ReflectionUtil
{

    /**
     * 缓存
     * @var array
     */
    public static $cache = [
        "getUsages" => []
    ];

    /**
     * 获取对象值的数据类型
     * @param mixed $concrete 类、闭包或者实例
     * @return string
     */
    public static function getType($concrete)
    {
        switch (gettype($concrete)) {
            case "string":
                if (class_exists(self::path($concrete))) {
                    return "class";
                }
                if (interface_exists(self::path($concrete))) {
                    return "interface";
                }
                if (strpos($concrete, "::") !== false) {
                    return self::getType(explode("::", $concrete));
                }
                if (is_file($concrete)) {
                    if (FileUtil::isPhpClassFile($concrete)) {
                        return "file php class";
                    } elseif (FileUtil::isPhpScriptFile($concrete)) {
                        return "file php script";
                    } else {
                        return "file";
                    }
                }
                if (is_dir($concrete)) {
                    return "dir";
                }
                break;
            case "array":
                if (count($concrete) == 2) {
                    if (is_object($concrete[0])) {
                        if (method_exists(...$concrete)) {
                            $reflect = new ReflectionMethod(...$concrete);
                            if ($reflect->isStatic()) {
                                return "class function";
                            } else {
                                return "object function";
                            }
                        } else if (method_exists($concrete[0], "__call")) {
                            return "object function";
                        }
                    } else if (class_exists(self::path($concrete[0]))) {
                        if (method_exists(...$concrete)) {
                            $reflect = new ReflectionMethod(...$concrete);
                            if ($reflect->isStatic()) {
                                return "class function";
                            } else {
                                return "object function";
                            }
                        } else if (method_exists($concrete[0], "__callStatic")) {
                            return "class function";
                        }
                    }
                } else if (count($concrete) == 1) {
                    if (is_object($concrete[0])) {
                        return "object";
                    } else if (class_exists(self::path($concrete[0]))) {
                        return "class";
                    }
                }
                break;
            case "object":
                if ($concrete instanceof Closure) {
                    return "closure";
                }
                break;
        }
        return gettype($concrete);
    }

    /**
     * 运行方法
     * @param $concrete
     * @param array $vars
     * @return mixed
     */
    public static function method($concrete, $vars = [])
    {
        try {
            switch (self::getType($concrete)) {
                case "class function":
                    if (is_string($concrete)) {
                        if (str_contains($concrete, "::")) {
                            return self::method(explode("::", $concrete), $vars);
                        }
                    } else if (is_array($concrete)) {
                        if (self::isMethod($concrete)) {
                            $reflect = new ReflectionMethod(...$concrete);
                            if ($reflect->isStatic()) {
                                return $reflect->invokeArgs(null, $vars);
                            }
                        } else if (self::isMethod([$concrete[0], "__callStatic"])) {
                            $reflect = new ReflectionMethod($concrete[0], "__callStatic");
                            return $reflect->invokeArgs(null, [$concrete[1], $vars]);
                        }
                    }
                    break;
                case "object function":
                    if (is_string($concrete)) {
                        if (str_contains($concrete, "::")) {
                            return self::method(explode("::", $concrete), $vars);
                        }
                    } else if (is_array($concrete)) {
                        if (self::isMethod($concrete)) {
                            $reflect = new ReflectionMethod(...$concrete);
                            if ($reflect->isStatic()) {
                                return $reflect->invokeArgs(null, $vars);
                            } else {
                                if ("beforeSubmit" === $concrete[1]) {
                                    return $reflect->invokeArgs(self::instance($concrete[0]), [&$vars[0], &$vars[1]]);
                                } else {
                                    return $reflect->invokeArgs(self::instance($concrete[0]), $vars);
                                }
                            }
                        } else if (self::isMethod([$concrete[0], "__call"])) {
                            $reflect = new ReflectionMethod($concrete[0], "__call");
                            return $reflect->invokeArgs($concrete[0], [$concrete[1], $vars]);
                        }
                    }
                    break;
                case "object":
                    if (self::isMethod([$concrete[0], "__construct"])) {
                        $reflect = new ReflectionMethod($concrete, "__construct");
                        return $reflect->invokeArgs($concrete, $vars);
                    }
                    break;
                case "closure":
                case "string":
                    $reflect = new ReflectionFunction($concrete);
                    return $reflect->invokeArgs($vars);
                case "class":
                    return self::instance($concrete, $vars);
            }
            throw new MethodNotFoundException('method not exists');
        } catch (ReflectionException $e) {
            throw new MethodNotFoundException($e->getMessage());
        }
    }

    /**
     * 是否是方法
     * @param $concrete
     * @return bool
     */
    public static function isMethod($concrete)
    {
        switch (self::getType($concrete)) {
            case "object function":
            case "class function":
                if (is_string($concrete)) {
                    if (str_contains($concrete, "::")) {
                        return self::isMethod(explode("::", $concrete));
                    }
                } else if (is_array($concrete)) {
                    return method_exists(...$concrete);
                }
                break;
            case "closure":
                return true;
            case "string":
                return function_exists($concrete);
        }
        return false;
    }

    /**
     * 是否是静态方法
     * @param $concrete
     * @return bool
     */
    public static function isMethodStatic($concrete)
    {
        switch (self::getType($concrete)) {
            case "object function":
            case "class function":
                if (is_string($concrete)) {
                    if (str_contains($concrete, "::")) {
                        return self::isMethodStatic(explode("::", $concrete));
                    }
                } else if (is_array($concrete)) {
                    if (method_exists(...$concrete)) {
                        $reflect = new ReflectionMethod(...$concrete);
                        return $reflect->isStatic();
                    } else {
                        return false;
                    }
                }
                break;
            case "class":
                return false;
            case "closure":
                return true;
            case "string":
                return function_exists($concrete);
        }
        return false;
    }

    /**
     * 创建实例
     * @param  $concrete
     * @param array $vars
     * @return mixed
     */
    public static function instance($concrete, $vars = [])
    {
        try {
            switch (self::getType($concrete)) {
                case "class function":
                    if (is_string($concrete)) {
                        if (str_contains($concrete, "::")) {
                            return self::instance(explode("::", $concrete));
                        }
                    } else if (is_array($concrete)) {
                        $instance = self::instance($concrete[0], ...$vars);
                        $reflect = new ReflectionMethod(null, $concrete[1]);
                        return $reflect->getClosure($instance);
                    }
                    break;
                case "object function":
                    if (is_string($concrete)) {
                        if (str_contains($concrete, "::")) {
                            return self::instance(explode("::", $concrete));
                        }
                    } else if (is_array($concrete)) {
                        $instance = self::instance($concrete[0], ...$vars);
                        $reflect = new ReflectionMethod($concrete[0], $concrete[1]);
                        return $reflect->getClosure($instance);
                    }
                    break;
                case "object":
                    return $concrete;
                case "string":
                case "closure":
                    $reflect = new ReflectionFunction($concrete);
                    return $reflect->getClosure();
                case "class":
                    $concrete = self::path($concrete);
                    $reflect = new ReflectionClass($concrete);
                    return $reflect->newInstance(...$vars);
            }
            throw new ClassNotFoundException('class not exists');
        } catch (ReflectionException $e) {
            throw new ClassNotFoundException($e->getMessage());
        }
    }

    /**
     * 对象属性值修改
     * @param $concrete
     * @param $name
     * @param $value
     * @return bool
     */
    public static function property($concrete, $name, $value)
    {
        try {
            if (self::getType($concrete) == "object") {
                if (property_exists($concrete, $name)) {
                    $reflect = new ReflectionClass($concrete);
                    $reflect->getProperty($name)->setValue($concrete, $value);
                    return true;
                }
                return false;
            } elseif (self::getType($concrete) == "class") {
                if (property_exists($concrete, $name)) {
                    $reflect = new ReflectionClass($concrete);
                    $property = $reflect->getProperty($name);
                    if ($property->isStatic()) {
                        $reflect->getProperty($name)->setValue($concrete, $value);
                        return true;
                    }
                }
                return false;
            }
            throw new ClassNotFoundException('class not exists');
        } catch (ReflectionException $e) {
            throw new ClassNotFoundException($e->getMessage());
        }
    }

    /**
     * 获取对象属性
     * @param $concrete
     * @param bool $self 访问范围
     * @param bool $type 访问类型
     * @return array
     */
    public static function getProperties($concrete, $self = true, $type = null)
    {
        try {
            if (self::getType($concrete) == "object") {
                $properties = [];
                $reflect = new ReflectionClass($concrete);
                foreach ($reflect->getProperties() as $property) {
                    if ($self && $property->class !== $reflect->getName()) {
                        continue;
                    }
                    if ($property->isStatic()) {
                        continue;
                    }
                    $properties[$property->getName()] = $property->getValue($concrete);
                }
                return $properties;
            } else if (self::getType($concrete) == "class") {
                $properties = [];
                $reflect = new ReflectionClass($concrete);
                foreach ($reflect->getProperties() as $property) {
                    if ($self && $property->class !== $reflect->getName()) {
                        continue;
                    }
                    if (!$property->isStatic()) {
                        continue;
                    }
                    $properties[$property->getName()] = $property->getValue();
                }
                return $properties;
            }
            throw new ClassNotFoundException('class not exists');
        } catch (ReflectionException $e) {
            throw new ClassNotFoundException($e->getMessage());
        }
    }

    /**
     * 获取对象属性
     * @param $concrete
     * @param $name
     * @param bool $type 访问类型
     * @return mixed
     */
    public static function getProperty($concrete, $name, $type = null)
    {
        try {
            if (self::getType($concrete) == "object") {
                if (property_exists($concrete, $name)) {
                    $reflect = new ReflectionClass($concrete);
                    $property = $reflect->getProperty($name);
                    $property->setAccessible(true);
                    return $property->getValue($concrete);
                }
            } else if (self::getType($concrete) == "class") {
                if (property_exists($concrete, $name)) {
                    $reflect = new ReflectionClass($concrete);
                    $property = $reflect->getProperty($name);
                    $property->setAccessible(true);
                    if ($property->isStatic()) {
                        return $reflect->getProperty($name)->getValue();
                    }
                }
            }
            throw new ClassNotFoundException('class not exists');
        } catch (ReflectionException $e) {
            throw new ClassNotFoundException($e->getMessage());
        }
    }

    /**
     * 获取对象常量
     * @param $concrete
     * @return void
     */
    public static function getConstants($concrete)
    {

    }

    /**
     * 获取对象常量
     * @param $concrete
     * @param $name
     * @return mixed
     */
    public static function getConstant($concrete, $name)
    {
        try {
            $reflect = new ReflectionClass($concrete);
            return $reflect->getConstant($name);
        } catch (ReflectionException $e) {
            throw new ClassNotFoundException($e->getMessage());
        }
    }

    /**
     * 获取对象方法
     * @param $concrete
     * @param bool $self 访问范围
     * @param bool $type 访问类型
     * @return array
     */
    public static function getMethods($concrete, $self = true, $type = null)
    {
        try {
            if (self::getType($concrete) == "object") {
                $methods = [];
                $reflect = new ReflectionClass($concrete);
                foreach ($reflect->getMethods() as $method) {
                    if ($self && $method->class !== $reflect->getName()) {
                        continue;
                    }
                    if ($method->isStatic() && $type != "class") {
                        continue;
                    }
                    $methods[$method->getName()] = $method;
                }
                return $methods;
            } else if (self::getType($concrete) == "class") {
                $methods = [];
                $reflect = new ReflectionClass($concrete);
                foreach ($reflect->getMethods() as $method) {
                    if ($self && $method->class !== $reflect->getName()) {
                        continue;
                    }
                    if (!$method->isStatic() && $type != "object") {
                        continue;
                    }
                    $methods[$method->getName()] = $method;
                }
                return $methods;
            }
            throw new ClassNotFoundException('class not exists');
        } catch (ReflectionException $e) {
            throw new ClassNotFoundException($e->getMessage());
        }
    }

    /**
     * 获取对象方法
     * @param $concrete
     * @param $name
     * @return mixed
     */
    public static function getMethod($concrete, $name)
    {
        try {
            if (self::getType($concrete) == "object") {
                if (property_exists($concrete, $name)) {
                    $reflect = new ReflectionClass($concrete);
                    $method = $reflect->getMethod($name);
                    $method->setAccessible(true);
                    return $method;
                }
            } else if (self::getType($concrete) == "class") {
                if (property_exists($concrete, $name)) {
                    $reflect = new ReflectionClass($concrete);
                    $method = $reflect->getMethod($name);
                    if ($method->isStatic()) {
                        return $method;
                    }
                }
            }
            throw new ClassNotFoundException('class not exists');
        } catch (ReflectionException $e) {
            throw new ClassNotFoundException($e->getMessage());
        }
    }

    /**
     * 获取方法参数
     * @param $concrete
     * @return mixed
     */
    public static function getMethodParams($concrete)
    {
        try {
            switch (self::getType($concrete)) {
                case "class function":
                case "object function":
                    if (is_string($concrete) && str_contains($concrete, "::")) {
                        return self::getMethodParams(explode("::", $concrete));
                    }
                    $reflect = new ReflectionMethod(...$concrete);
                    $params = [];
                    foreach ($reflect->getParameters() as $param) {
                        $params[] = $param->getName();
                    }
                    return $params;
                case "closure":
                case "string":
                    $reflect = new ReflectionFunction($concrete);
                    $params = [];
                    foreach ($reflect->getParameters() as $param) {
                        $params[] = $param->getName();
                    }
                    return $params;
                case "object":
                    $reflect = new ReflectionMethod($concrete, "__construct");
                    $params = [];
                    foreach ($reflect->getParameters() as $param) {
                        $params[] = $param->getName();
                    }
                    return $params;
                case "class":
                    $concrete = self::path($concrete);
                    $reflect = new ReflectionMethod($concrete, "__construct");
                    $params = [];
                    foreach ($reflect->getParameters() as $param) {
                        $params[] = $param->getName();
                    }
                    return $params;
            }
            throw new ClassNotFoundException('class not exists');
        } catch (ReflectionException $e) {
            throw new ClassNotFoundException($e->getMessage());
        }
    }

    /**
     * 获取值类型返回值
     * @return void
     */
    public static function getReturnClass($concrete)
    {
        return ReflectionUtil::getAnnotationByClass($concrete, VarWrapper::class);
    }

    /**
     * 获取方法参数
     * @param $concrete
     * @param $name
     * @return mixed
     */
    public static function getMethodParam($concrete, $name)
    {
        try {
            switch (self::getType($concrete)) {
                case "class function":
                case "object function":
                    if (is_string($concrete) && str_contains($concrete, "::")) {
                        return self::getMethodParams(explode("::", $concrete));
                    }
                    $reflect = new ReflectionMethod(...$concrete);
                    foreach ($reflect->getParameters() as $param) {
                        if ($name == $param->getName()) {
                            $values = [
                                "name" => $param->getName(),
                            ];
                            if ($param->isDefaultValueAvailable()) {
                                $values["default"] = $param->getDefaultValue();
                            }
                            return $values;
                        }
                    }
                    break;
                case "closure":
                case "string":
                    $reflect = new ReflectionFunction($concrete);
                    foreach ($reflect->getParameters() as $param) {
                        if ($name == $param->getName()) {
                            $values = [
                                "name" => $param->getName(),
                            ];
                            if ($param->isDefaultValueAvailable()) {
                                $values["default"] = $param->getDefaultValue();
                            }
                            return $values;
                        }
                    }
                    break;
                case "object":
                    $reflect = new ReflectionMethod($concrete, "__construct");
                    foreach ($reflect->getParameters() as $param) {
                        if ($name == $param->getName()) {
                            $values = [
                                "name" => $param->getName(),
                            ];
                            if ($param->isDefaultValueAvailable()) {
                                $values["default"] = $param->getDefaultValue();
                            }
                            return $values;
                        }
                    }
                    break;
                case "class":
                    $concrete = self::path($concrete);
                    $reflect = new ReflectionMethod($concrete, "__construct");
                    foreach ($reflect->getParameters() as $param) {
                        if ($name == $param->getName()) {
                            $values = [
                                "name" => $param->getName(),
                            ];
                            if ($param->isDefaultValueAvailable()) {
                                $values["default"] = $param->getDefaultValue();
                            }
                            return $values;
                        }
                    }
                    break;
            }
            throw new ClassNotFoundException('class not exists ' . $name);
        } catch (ReflectionException $e) {
            throw new ClassNotFoundException($e->getMessage());
        }
    }

    /**
     * 获取命名空间
     * @param $concrete
     * @return string|null
     */
    public static function getNamespace($concrete)
    {
        try {
            switch (self::getType($concrete)) {
                case "class function":
                case "object function":
                    if (is_string($concrete) && str_contains($concrete, "::")) {
                        return self::getNamespace(explode("::", $concrete));
                    }
                    if (is_string($concrete[0])) {
                        $reflect = new ReflectionClass(self::path($concrete[0]));
                    } else {
                        $reflect = new ReflectionClass($concrete[0]);
                    }
                    return $reflect->getNamespaceName();
                case "file php class":
                    $content = FileUtil::read($concrete);
                    $fileLines = preg_split("/\r\n|\n|\r/", $content);
                    foreach ($fileLines as $fileLine) {
                        $fileLine = StrUtil::trim($fileLine);
                        if (StrUtil::startsWith($fileLine, "namespace")) {
                            $values = StrUtil::sub($fileLine, 9, (strlen($fileLine) - 10));
                            $params = StrUtil::split(StrUtil::trim($values), " ");
                            if (count($params) === 1) {
                                return $params[0];
                            }
                        }
                    }
                    return null;
                case "object":
                    $reflect = new ReflectionClass($concrete);
                    return $reflect->getNamespaceName();
                case "class":
                    $concrete = self::path($concrete);
                    $reflect = new ReflectionClass($concrete);
                    return $reflect->getNamespaceName();
                case "string":
                case "closure":
                    $reflect = new ReflectionFunction($concrete);
                    return $reflect->getNamespaceName();
            }
            return null;
        } catch (ReflectionException $e) {
            throw new ClassNotFoundException($e->getMessage());
        }
    }

    /**
     * 获取对象 class
     * @param $concrete
     * @return string|null
     */
    public static function getClass($concrete)
    {
        try {
            switch (self::getType($concrete)) {
                case "class function":
                case "object function":
                    if (is_string($concrete) && str_contains($concrete, "::")) {
                        return self::getName(explode("::", $concrete));
                    }
                    if (is_string($concrete[0])) {
                        $reflect = new ReflectionClass(self::path($concrete[0]));
                    } else {
                        $reflect = new ReflectionClass($concrete[0]);
                    }
                    return $reflect->getName();
                case "file php class":
                    $name = self::getName($concrete);
                    $namespace = self::getNamespace($concrete);
                    return StrUtil::hasNotEmpty($namespace) ? $namespace . "\\" . $name : $name;
                case "object":
                    $reflect = new ReflectionClass($concrete);
                    return $reflect->getName();
                case "class":
                    $concrete = self::path($concrete);
                    $reflect = new ReflectionClass($concrete);
                    return $reflect->getName();
                case "string":
                    if (function_exists($concrete)) {
                        $reflect = new ReflectionFunction($concrete);
                        return $reflect->getName();
                    } else {
                        return "string";
                    }
                case "closure":
                    $reflect = new ReflectionFunction($concrete);
                    return $reflect->getName();
            }
            return null;
        } catch (ReflectionException $e) {
            throw new ClassNotFoundException($e->getMessage());
        }
    }

    /**
     * 类反射
     * @param $clz
     * @return ReflectionClass
     */
    public static function reflectionClass($clz)
    {
        try {
            return new ReflectionClass($clz);
        } catch (ReflectionException $e) {
            throw new ClassNotFoundException($e->getMessage());
        }
    }

    /**
     * 获取对象注解 class
     * @param $concrete
     * @return mixed
     */
    public static function getAnnotation($concrete)
    {
        return null;
    }

    /**
     * 获取对象注解 class
     * @param $concrete
     * @return mixed
     */
    public static function getAnnotationByName($concrete)
    {
        return null;
    }

    /**
     * 获取对象注解 class
     * @param $concrete
     * @param $annotation
     * @return mixed
     */
    public static function getAnnotationByClass($concrete, $annotation)
    {
        $annotations = self::getAnnotations($concrete);
        foreach ($annotations as $item) {
            if ($annotation === self::getClass($item)) {
                return $item;
            }
        }
        return null;
    }

    /**
     * 获取对象注解 class
     * @param $concrete
     * @return array
     */
    public static function getAnnotations($concrete)
    {
        $annotations = [];
        if ($concrete instanceof ReflectionProperty) {
            $usages = ReflectionUtil::getUsages($concrete->class);
            $docComments = $concrete->getDocComment();
        }
        if ($concrete instanceof ReflectionMethod) {
            $usages = ReflectionUtil::getUsages($concrete->class);
            $docComments = $concrete->getDocComment();
        } else {
            $usages = ReflectionUtil::getUsages($concrete);
            $reflect = self::reflectionClass($concrete);
            $docComments = $reflect->getDocComment();
        }
        $docCommentLines = preg_split("/\r\n|\n|\r/", $docComments);
        foreach ($docCommentLines as $docCommentLine) {
            $docCommentLine = StrUtil::trim($docCommentLine);
            if (preg_match('/^\s*\*\s*@(\w+)/', $docCommentLine, $docCommentBaseData)) {
                $isAnnotation = false;
                foreach ($usages as $usage) {
                    if ($usage->getName() === $docCommentBaseData[1]) {
                        $isAnnotation = true;
                    }
                }
                if ($docCommentBaseData[1] === "var") {
                    $docCommentBaseData[1] = "\\" . VarWrapper::class;
                    $isAnnotation = true;
                } else if ($docCommentBaseData[1] === "param") {
                    $docCommentBaseData[1] = "\\" . ParamWrapper::class;
                    $isAnnotation = true;
                } else if ($docCommentBaseData[1] === "return") {
                    $docCommentBaseData[1] = "\\" . ReturnWrapper::class;
                    $isAnnotation = true;
                }
                if ($isAnnotation) {
                    if (preg_match('/^\s*\*\s*@(\w+)\(([\s\S]*)\)/', $docCommentLine, $docCommentData)) {
                        $annotations[] = PhpScriptUtil::expression("new " . $docCommentBaseData[1] . "(" . $docCommentData[2] . ")", [], $usages);
                    } else if (preg_match('/^\s*\*\s*@(\w+)\s*([\s\S]*)/', $docCommentLine, $docCommentData)) {
                        $params = ShellUtil::params($docCommentData[2]);
                        foreach ($params as &$param) {
                            $param = StrUtil::replace("\"", "\\\"", $param);
                            $param = StrUtil::join(["\"", $param, "\""], "");
                        }
                        $annotations[] = PhpScriptUtil::expression("new " . $docCommentBaseData[1] . "(" . StrUtil::join($params, ",") . ")", [], $usages);
                    } else if (preg_match('/^\s*\*\s*@(\w+)/', $docCommentLine, $docCommentData)) {
                        $annotations[] = PhpScriptUtil::expression("new " . $docCommentBaseData[1] . "()", [], $usages);
                    }
                }
            }
        }
        return $annotations;
    }

    /**
     * 获取对象 class
     * @param $concrete
     * @return Usage[]
     */
    public static function getUsages($concrete)
    {
        $usages = [];
        $reflect = self::reflectionClass(self::getClass($concrete));
        $filePath = $reflect->getFileName();
        if ($filePath !== false) {
            if (StrUtil::endsWith($filePath, " : eval()'d code")) {
                return $usages;
            }
            if (isset(self::$cache["getUsages"][$filePath])
                && self::$cache["getUsages"][$filePath]["createTime"] == FileUtil::createTime($filePath)
                && self::$cache["getUsages"][$filePath]["updateTime"] == FileUtil::updateTime($filePath)) {
                ++self::$cache["getUsages"][$filePath]["readCount"];
                self::$cache["getUsages"][$filePath]["readTime"] = DateUtil::date();
                return self::$cache["getUsages"][$filePath]['usages'];
            }
            $namespace = self::getNamespace($concrete);
            $dirs = DirUtil::get(dirname($filePath));
            foreach ($dirs as $dir) {
                if ($dir['type'] === "file" && $filePath !== $dir['path']) {
                    if ($dir['extension'] === "php") {
                        $usage = new Usage();
                        $usage->setName($dir['baseName']);
                        $usage->setType("class");
                        $usage->setPath($namespace . "\\" . $usage->getName());
                        $usage->setRaw("use " . $usage->getPath() . ";");
                        $usages[] = $usage;
                    }
                }
            }
            $fileContent = FileUtil::read($filePath);
            $fileLines = preg_split("/\r\n|\n|\r/", $fileContent);
            $startNameSpace = 0;
            for ($i = 0; $i < count($fileLines); $i++) {
                $fileLine = $fileLines[$i];
                if (StrUtil::hasNotEmpty($fileLine)) {
                    if (StrUtil::startsWith($fileLine, "namespace ")) {
                        $startNameSpace = $i;
                        continue;
                    }
                    if (StrUtil::startsWith($fileLine, ["class ", "abstract class "])) {
                        $i = count($fileLines);
                        continue;
                    }
                    if ($startNameSpace > 0) {
                        if (StrUtil::startsWith($fileLine, "use function ")) {
                            $values = StrUtil::sub($fileLine, 13, (strlen($fileLine) - 14));
                            $params = StrUtil::split(StrUtil::trim($values), " ");
                            if (count($params) === 1) {
                                $usage = new Usage();
                                $usage->setName(PathUtil::name($params[0]));
                                $usage->setType("function");
                                $usage->setPath($params[0]);
                                $usage->setRaw($fileLine);
                                $usages[] = $usage;
                            } else if (count($params) === 3) {
                                if ($params[1] === "as") {
                                    $usage = new Usage();
                                    $usage->setName($params[2]);
                                    $usage->setAs($params[2]);
                                    $usage->setType("function");
                                    $usage->setPath($params[0]);
                                    $usage->setRaw($fileLine);
                                    $usages[] = $usage;
                                }
                            }
                        } else if (StrUtil::startsWith($fileLine, "use const ")) {
                            $values = StrUtil::sub($fileLine, 10, (strlen($fileLine) - 11));
                            $params = StrUtil::split(StrUtil::trim($values), " ");
                            if (count($params) === 1) {
                                $usage = new Usage();
                                $usage->setName(PathUtil::name($params[0]));
                                $usage->setType("const");
                                $usage->setPath($params[0]);
                                $usage->setRaw($fileLine);
                                $usages[] = $usage;
                            } else if (count($params) === 3) {
                                if ($params[1] === "as") {
                                    $usage = new Usage();
                                    $usage->setName($params[2]);
                                    $usage->setAs($params[2]);
                                    $usage->setType("const");
                                    $usage->setPath($params[0]);
                                    $usage->setRaw($fileLine);
                                    $usages[] = $usage;
                                }
                            }
                        } else if (StrUtil::startsWith($fileLine, "use ")) {
                            $values = StrUtil::sub($fileLine, 4, (strlen($fileLine) - 5));
                            $params = StrUtil::split(StrUtil::trim($values), " ");
                            if (count($params) === 1) {
                                $usage = new Usage();
                                $usage->setName(PathUtil::name($params[0]));
                                $usage->setType("class");
                                $usage->setPath($params[0]);
                                $usage->setRaw($fileLine);
                                $usages[] = $usage;
                            } else if (count($params) === 3) {
                                if ($params[1] === "as") {
                                    $usage = new Usage();
                                    $usage->setName($params[2]);
                                    $usage->setAs($params[2]);
                                    $usage->setType("class");
                                    $usage->setPath($params[0]);
                                    $usage->setRaw($fileLine);
                                    $usages[] = $usage;
                                }
                            }
                        }
                    }
                }
            }
            self::$cache["getUsages"][$filePath] = [
                'readCount' => 1,
                'readTime' => DateUtil::date(),
                'usages' => $usages,
                'createTime' => FileUtil::createTime($filePath),
                'updateTime' => FileUtil::updateTime($filePath)
            ];
        }
        return ArrayUtil::distinct($usages, "raw");
    }

    /**
     * 获取引用的类
     * @return void
     */
    public static function getUsagesClass($class, $useClass)
    {
        $usages = ReflectionUtil::getUsages($class);
        foreach ($usages as $usage) {
            if ($usage->getName() === $useClass) {
                return $usage->getPath();
            }
        }
        return null;
    }

    /**
     * 获取名称
     * @param $concrete
     * @return string|null
     */
    public static function getName($concrete)
    {
        try {
            switch (self::getType($concrete)) {
                case "class function":
                case "object function":
                    if (is_string($concrete) && str_contains($concrete, "::")) {
                        return self::getName(explode("::", $concrete));
                    }
                    if (is_string($concrete[0])) {
                        $reflect = new ReflectionClass(self::path($concrete[0]));
                    } else {
                        $reflect = new ReflectionClass($concrete[0]);
                    }
                    return $reflect->getShortName();
                case "file php class":
                    $content = FileUtil::read($concrete);
                    $fileLines = preg_split("/\r\n|\n|\r/", $content);
                    foreach ($fileLines as $fileLine) {
                        if (StrUtil::startsWith(StrUtil::trim($fileLine), "class")) {
                            $values = StrUtil::sub($fileLine, 5, (strlen($fileLine) - 5));
                            $params = StrUtil::split(StrUtil::trim($values), " ");
                            if (count($params) > 0) {
                                return $params[0];
                            }
                        }
                    }
                    return null;
                case "array":
                    $reflect = new ReflectionMethod(...$concrete);
                    return $reflect->getShortName();
                case "closure":
                    return null;
                case "string":
                    $reflect = new ReflectionFunction($concrete);
                    return $reflect->getShortName();
                case "object":
                    $reflect = new ReflectionClass($concrete);
                    return $reflect->getShortName();
                case "interface":
                case "class":
                    $concrete = self::path($concrete);
                    $reflect = new ReflectionClass($concrete);
                    return $reflect->getShortName();
            }
            throw new ClassNotFoundException('class not exists');
        } catch (ReflectionException $e) {
            throw new ClassNotFoundException($e->getMessage());
        }
    }

    /**
     * 获取父类 class
     * @param $concrete
     * @return false|ReflectionClass
     */
    public static function getFatherClass($concrete)
    {
        try {
            if (self::getType($concrete) == "object") {
                $reflect = new ReflectionClass($concrete);
                return $reflect->getParentClass();
            } elseif (self::getType($concrete) == "class") {
                $reflect = new ReflectionClass($concrete);
                return $reflect->getParentClass();
            } elseif (self::getType($concrete) == "string") {
                $reflect = new ReflectionClass($concrete);
                return $reflect->getParentClass();
            }
            return null;
        } catch (ReflectionException $e) {
            throw new ClassNotFoundException($e->getMessage());
        }
    }

    /**
     * 获取当前类的接口
     * @param $concrete
     * @return ReflectionClass[]
     */
    public static function getInterfaces($concrete)
    {
        try {
            if (self::getType($concrete) == "object") {
                $reflect = new ReflectionClass($concrete);
                return $reflect->getInterfaces();
            } elseif (self::getType($concrete) == "class") {
                $reflect = new ReflectionClass($concrete);
                return $reflect->getInterfaces();
            } elseif (self::getType($concrete) == "string") {
                $reflect = new ReflectionClass($concrete);
                return $reflect->getInterfaces();
            }
            return [];
        } catch (ReflectionException $e) {
            throw new ClassNotFoundException($e->getMessage());
        }
    }

    /**
     * 判断是否存在
     * @return bool
     */
    public static function exists($concrete)
    {
        if (class_exists($concrete)) {
            return true;
        }
        return false;
    }

    /**
     * 判断不存在
     * @param $concrete
     * @return bool
     */
    public static function notExists($concrete)
    {
        if (class_exists($concrete)) {
            return false;
        }
        return true;
    }

    /**
     * 路径转换
     * @param $path
     * @return string
     */
    private static function path($path)
    {
        return str_replace("/", "\\", $path);
    }

}